﻿using FlashPay.DAO.Interface;
using FlashPay.EF.Models;
using FlashPay.Entity.DAORequest.User;
using FlashPay.Entity.DAORequest.Company;
using FlashPay.Service.Interface;
using FlashPay.Util;
using FlashPay.Util.StatusCode;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using FlashPay.Entity.LogAffect;
using FlashPay.Entity.Enum;

namespace FlashPay.Service.Shared
{
    public class BaseService
    {
        protected CompanyDao companyDAO;
        protected SysRoleDao sysRoleDao;
        protected UserInfoDao userInfoDao;
        protected LogDao logDao;

        protected StatusCodeFactory statusCodeFactory;

        protected AuthService authService;

        protected LogRecord logRecord;

        /// <summary>
        /// 取得時間
        /// </summary>
        protected virtual DateTime GetNowDateTime()
        {
            return DateTime.Now;
        }

        /// <summary>
        /// 創建公司DAO請求物件
        /// </summary>
        protected CompanyRequest CreateCompanyRequest()
        {
            CompanyRequest request = new CompanyRequest();
            request.CompanyPid = -1;

            return request;
        }

        /// <summary>
        /// 公司取得(單筆)
        /// </summary>
        protected EF.Models.Company GetCompany(CompanyRequest request)
        {
            BaseModel<List<EF.Models.Company>> model = new BaseModel<List<EF.Models.Company>>();

            /* 呼叫DAO層 */
            companyDAO.Get(model, request);

            if (!model.Success || model.Result.Count != 1)
            {
                return null;
            }

            return model.Result[0];
        }

        /// <summary>
        /// 公司取得(多筆)
        /// </summary>
        protected List<EF.Models.Company> GetCompanies(CompanyRequest request, Int32 level = 1)
        {
            BaseModel<List<EF.Models.Company>> model = new BaseModel<List<EF.Models.Company>>();
            model.PageSize = Int32.MaxValue;

            /* 呼叫DAO層 */
            companyDAO.Get(model, request, level);

            if (!model.Success)
            {
                return null;
            }

            return model.Result;
        }

        /// <summary>
        /// 確認公司關聯性
        /// </summary>
        protected Boolean CheckCompanyRelevance(Int32 parentCompanyId, Int32 subCompanyId, Int32 level = 2, Boolean excludeDeleted = true)
        {
            /* 若查詢上下層關係，帶入 subCompanyId 可簡化至一次查詢 */
            if (level < 3)
            {
                List<Int32> ids = _GetRelatedCompany(parentCompanyId: parentCompanyId, subCompanyId: subCompanyId, excludeDeleted: excludeDeleted);

                return ids != null && ids.Count == 1;
            }
            /* 若查詢多層關係，須利用 level 獲取所有相關 CompanyID 後檢查 subCompanyId 是否存在 */
            else
            {
                List<Int32> ids = _GetRelatedCompany(parentCompanyId: parentCompanyId, level: level, excludeDeleted: excludeDeleted);

                return ids == null || ids.Count == 0 ? false : ids.Contains(subCompanyId);
            }
        }

        /// <summary>
        /// 獲取相關公司ID
        /// </summary>
        protected List<Int32> GetRelatedCompany(Int32 parentCompanyId, Int32 level = 2, Boolean excludeDeleted = true)
        {
            return _GetRelatedCompany(parentCompanyId: parentCompanyId, level: level, excludeDeleted: excludeDeleted);
        }

        /// <summary>
        /// 獲取相關公司ID
        /// </summary>
        private List<Int32> _GetRelatedCompany(Int32 parentCompanyId, Int32 subCompanyId = 0, Int32 level = 2, Boolean excludeDeleted = true)
        {
            CompanyRequest request = CreateCompanyRequest();

            if (subCompanyId == 0)
            {
                request.CompanyId = parentCompanyId;
            }
            else
            {
                level = 1;
                request.CompanyId = subCompanyId;
                request.CompanyPid = parentCompanyId;
            }

            if (excludeDeleted)
            {
                request.NotCompanyStatus = (SByte)CompanyStatus.删除;
            }

            if (level < 1)
            {
                level = 1;
            }

            List<EF.Models.Company> companies = GetCompanies(request, level);

            return companies == null ? null : companies.Select(company => company.CompanyId).ToList();
        }

        /// <summary>
        /// 角色數取得
        /// </summary>
        protected Int32? GetSysRoleCount(SysRole request)
        {
            BaseModel<List<SysRole>> model = new BaseModel<List<SysRole>>();

            /* 呼叫DAO層 */
            sysRoleDao.Get(model, request);

            /* 檢查資料 */
            if (!model.Success)
            {
                return null;
            }

            return model.Result.Count;
        }

        /// <summary>
        /// 用戶數取得
        /// </summary>
        protected Int32? GetUserInfoCount(UserRequest request)
        {
            BaseModel<List<UserInfo>> model = new BaseModel<List<UserInfo>>();

            /* 呼叫DAO層 */
            userInfoDao.Get(model, request);

            /* 檢查資料 */
            if (!model.Success)
            {
                return null;
            }

            return model.Result.Count;
        }

        /// <summary>
        /// 確認用戶關聯性(用戶可視範圍為所屬公司及一層子公司)
        /// </summary>
        protected Boolean CheckUserRelevance(Int32 userId, Int32 companyId)
        {
            List<Int32> ids = _GetRelatedUser(companyId, userId);

            return ids != null && ids.Count == 1;
        }

        /// <summary>
        /// 獲取相關用戶ID(用戶可視範圍為所屬公司及一層子公司)
        /// </summary>
        protected List<Int32> GetRelatedUser(Int32 companyId)
        {
            return _GetRelatedUser(companyId);
        }

        /// <summary>
        /// 獲取相關用戶ID
        /// </summary>
        private List<Int32> _GetRelatedUser(Int32 companyId, Int32 userId = 0)
        {
            /* 準備資料 */
            BaseModel<List<EF.Models.Company>> model = new BaseModel<List<EF.Models.Company>>();
            model.PageSize = Int32.MaxValue;
            CompanyRequest query = CreateCompanyRequest();

            /* 如果 CompanyID 為 0 表示該用戶為admin，需改變搜索條件 */
            if (companyId == 0)
            {
                query.CompanyPid = companyId;
            }
            else
            {
                query.CompanyId = companyId;
            }

            /* 呼叫DAO層 */
            companyDAO.Get(model, query, 2);

            /* 資料檢查 */
            if (model.Success && model.Result.Count > 0)
            {
                /* 準備資料 */
                BaseModel<List<UserInfo>> model2 = new BaseModel<List<UserInfo>>();
                model2.PageSize = Int32.MaxValue;

                UserRequest query2 = new UserRequest();
                query2.CompanyID = model.Result.Select(data => data.CompanyId).ToList();

                if (userId > 0)
                {
                    query2.UserID = new List<Int32>() { userId };
                }

                /* 呼叫DAO層 */
                userInfoDao.Get(model2, query2);

                if (model2.Success)
                {
                    return model2.Result.Select(data => data.UId).ToList();
                }
            }

            return null;
        }

        /// <summary>
        /// 紀錄Log
        /// </summary>
        protected void AddLog(SByte logLevel, Int32 logType, Object requestData, String logRemark, LogAffectData affectData = null)
        {
            LogRecord log = new LogRecord();
            log.LogLevel = logLevel;
            log.LogType = logType;
            log.LogRemark = logRemark;
            log.CreateDate = DateTime.Now;

            if (logRecord != null)
            {
                log.CompanyId = logRecord.CompanyId;
                log.CreateName = logRecord.CreateName ?? "";
                log.CreateUid = logRecord.CreateUid;
                log.RequestUrl = logRecord.RequestUrl ?? "";
                log.Ip = logRecord.Ip;
            }

            if (requestData != null)
            {
                log.RequestData = JsonConvert.SerializeObject(requestData);
            }

            if (affectData != null)
            {
                log.AffectData = JsonConvert.SerializeObject(affectData);
            }

            logDao.Insert(log);
        }

        /// <summary>
        /// 複製物件
        /// </summary>
        protected T CloneObject<T>(T source)
        {
            // Don't serialize a null object, simply return the default for that object
            if (Object.ReferenceEquals(source, null))
            {
                return default(T);
            }

            // initialize inner objects individually
            // for example in default constructor some list property initialized with some values,
            // but in 'source' these items are cleaned -
            // without ObjectCreationHandling.Replace default constructor values will be added to result
            var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };

            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
        }

        /// <summary>
        /// 隱蔽資訊替換成* 
        /// </summary>
        protected String HiddenInfo(String value, Int32 front = 0, Int32 behind = 0, Boolean isReserve = false)
        {
            Int32 len = value.Length;
            Int32 temp = 0;
            Char[] c = value.ToArray();

            if (isReserve)
            {
                Int32 si = 0;
                Int32 ei = len;

                if (front > 0)
                {
                    si = front;
                }

                if (behind > 0)
                {
                    ei -= behind;
                }

                if (si <= ei)
                {
                    for (; si < ei; si++)
                    {
                        c[si] = '*';
                    }
                }
            }
            else
            {
                if (front > 0)
                {
                    temp = front >= len ? len : front;
                    for (Int32 i = 0; i < temp; i++)
                    {
                        c[i] = '*';
                    }
                }

                if (behind > 0)
                {
                    temp = behind >= len ? len : behind;
                    for (Int32 i = 0; i < temp; i++)
                    {
                        c[len - 1 - i] = '*';
                    }
                }
            }

            return new String(c);
        }
    }
}
